dirFrom=${gitRepoHub}/${sequence}/${gitRepoHome}/${targetBundleFrom}
dirOut=${gitRepoHub}/${sequence}/${gitRepoHome}/${targetBundleTo}
dirTo=${dirOut}/${sequence}/${targetBundleName}
targetPackScript=${targetPackScript:-aundle.sh}
bundle=${sequence}.${targetBundleName}.tar.gz
targetBundleEntryScript=app.sh
targetBundle=${targetBundleHub}/${bundle}
targetBundleDir=${targetBundleHub}/${sequence}/${targetBundleName}
targetBackupFile=${targetBackupHub}/${sequence}.${targetBundleName}.tar.gz

function pack() {
    set -e
    if [[ -f ${targetPackScript} ]]; then
        bash ${targetPackScript} ${action} ${targetResource} ${sequence} ${executeProfile}
        return 0
    fi

    rm -rf ${dirTo}
    mkdir -p ${dirTo}

    cd ${dirFrom}
    for item in $(ls .); do
          cp -r ${item} ${dirTo}
    done
    cd ${dirOut}

    cmd="tar -cvzf ${bundle} ${sequence}"
    logger "${cmd}"
    while read -r line; do logger "${line}"; done < <(${cmd} 2>&1)

}

function collect() {
    set -e
    timestamp=$(date "+%Y%m%d%H%M%S")
    if [[ ${targetBundleHubLocal} == ${dirOut} ]]; then loggrer "No need to collect"; pass; fi
    cd ${targetBundleHubLocal}
    if [ -f ${bundle} ]; then logger "Backup bundle with same sequence"; mv ${bundle} ${bundle}.${timestamp}; fi
    logger ${dirOut}/${bundle}
    logger ${targetBundleHubLocal}/${bundle}
    cp ${dirOut}/${bundle} .
}

function sshSend() {

    #强制分发[[ $1 == 0 ]]

    #需要判断远程状态后继续操作，所以不能立刻退出脚本
    set +e
    cd ${targetBundleHubLocal}

    #是否分发
    ssh ${user}@${host} "[[ -f ${targetBundleHub}/${bundle} ]]"
    if [[ $? == 0 && -z $1 ]]; then
        logger "Already send."
        return 0
    fi
    ssh ${user}@${host} "if [[ $1 == 0 && ! -z ${bundle} ]]; then mv ${targetBundleHub}/${bundle} ${targetBundleHub}/${bundle}.$(date "+%Y%m%d%H%M%S") ; fi"

    #能否分发
    if [[ ! -f ${bundle} ]]; then
        logger "Package ${bundle} not found." "error"
        return 1
    fi
    ssh ${user}@${host} "[[ -d ${targetBundleHub} ]]"
    if [[ ! $? == 0 ]]; then
        logger "TargetBundleDir ${targetBundleHub} not found."
        ssh ${user}@${host} "mkdir -p ${targetBundleHub}"
        if [[ ! $? == 0 ]];
            then
                logger "Failed to create targetBundleHub ${targetBundleHub}" "error"
                return 1
            else
                logger "TargetBundleDir ${targetBundleHub} created."
        fi
    fi

    #分发
    logger "Send ${bundle} to ${user}@${host}:${targetBundleHub}"
    scp ${bundle} ${user}@${host}:${targetBundleHub}
    if [[ $? == 0 ]];
        then
            logger "Succeed to send ${bundle}"
            return 0
        else
            logger "Failed to send ${bundle}" "error"
            return 1
    fi
}

#function upload() {
#    set -e
#    pass
#}

#function sshUpload() {
#    set -e
#    pass
#}

#function download() {
#    set -e
#    pass
#}

#function sshDownload() {
#    set -e
#    pass
#}

function unpack () {
    set -e
    #是否解包
    if [[ -d ${targetBundleDir}  ]]; then
        logger "Already unpacked ${targetBundleDir}"
        return 0
    fi

    #能否解包
    if [[ ! -f ${targetBundle}  ]]; then
        logger "Package ${targetBundle} not found." "error"
        return 1
    fi

    #解包
    cmd="tar -xzvf ${targetBundle} -C ${targetBundleHub}"
    logger "${cmd}"
    while read -r line; do logger "${line}"; done < <(${cmd} 2>&1)

    logger "Succeed to unpack ${targetBundle}."
    return 0
}

function sshUnpack () {
    set +e
    ssh ${user}@${host} "
    action=${action}
    targetResource=${targetResource}
    targetBundle=${targetBundle}
    targetBundleDir=${targetBundleDir}
    targetBundleHub=${targetBundleHub}
    $(typeset -f checkIpAddress)
    $(typeset -f checkUser)
    $(typeset -f checkRevoker)
    $(typeset -f logger)
    $(typeset -f unpack)
    unpack
    "
    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
    logger "Succeed ${action} ${targetBundle}"
    set -e
    return 0
}

function unpackForce () {
    set -e
    if [[ -d ${targetBundleDir}  ]]; then
        rm -rf ${targetBundleDir}
        logger "Succeed to remove  ${targetBundleDir}."
    fi
    unpack
}

function sshUnpackForce () {
    set +e
    ssh ${user}@${host} "
    action=${action}
    targetResource=${targetResource}
    targetBundle=${targetBundle}
    targetBundleDir=${targetBundleDir}
    targetBundleHub=${targetBundleHub}
    $(typeset -f checkIpAddress)
    $(typeset -f checkUser)
    $(typeset -f checkRevoker)
    $(typeset -f logger)
    $(typeset -f unpack)
    $(typeset -f unpackForce)
    unpackForce
    "
    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
    logger "Succeed ${action} ${targetBundle}"
    set -e
    return 0
}

function todo () {
    set -e
    timestamp=$(date "+%Y%m%d%H%M%S")
    #是否执行
    #能否执行
    if [[ ! -f ${targetBundleDir}/${targetBundleEntryScript}  ]]; then
        logger "Entry script ${targetBundleDir}/${targetBundleEntryScript} not found."
        return 1
    fi
    #执行
    cd ${targetBundleDir}
    #bash ${targetBundleEntryScript} todo ${sequence}  ${executeProfile} 2>&1 | tee -a ${timestamp}.log
    cmd="bash ${targetBundleEntryScript} todo ${sequence}  ${executeProfile} | tee -a ${timestamp}.log"
    logger "${barEqual30}${barEqual30}${barEqual30}"
    logger "[todo] ${cmd}"
    logger "${barEqual30}${barEqual30}${barEqual30}"
    while read -r line; do logger "[todo] ${line}"; done < <(${cmd} 2>&1)
    logger "${barEqual30}${barEqual30}${barEqual30}"

    if (( $? != 0 )); then
        logger "Failed todo." "error"
        return 1
    fi
    return 0
}

function sshTodo () {
    set +e
    ssh ${user}@${host} "
    action=${action}
    targetResource=${targetResource}
    sequence=${sequence}
    executeProfile=${executeProfile}
    targetBundleDir=${targetBundleDir}
    targetBundleEntryScript=${targetBundleEntryScript}
    barEqual30=${barEqual30}
    $(typeset -f checkIpAddress)
    $(typeset -f checkUser)
    $(typeset -f checkRevoker)
    $(typeset -f logger)
    $(typeset -f todo)
    todo
    "
    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
    logger "Succeed ${action} ${targetBundle}"
    set -e
    return 0
}

function undo () {
    set -e
    timestamp=$(date "+%Y%m%d%H%M%S")
    #是否执行
    #能否执行
    if [[ ! -f ${targetBundleDir}/${targetBundleEntryScript}  ]]; then
        logger "Entry script ${targetBundleDir}/${targetBundleEntryScript} not found." "error"
        return 1
    fi
    #执行
    cd ${targetBundleDir}

    #bash ${targetBundleEntryScript} undo ${sequence}  ${executeProfile} 2>&1 | tee -a ${timestamp}.log
    cmd="bash ${targetBundleEntryScript} undo ${sequence}  ${executeProfile} | tee -a ${timestamp}.log"
    logger "${barEqual30}${barEqual30}${barEqual30}"
    logger "[undo] ${cmd}"
    logger "${barEqual30}${barEqual30}${barEqual30}"
    while read -r line; do logger "[undo] ${line}"; done < <(${cmd} 2>&1)
    logger "${barEqual30}${barEqual30}${barEqual30}"

    if (( $? != 0 )); then
        logger "Failed undo." "error"
        return 1
    fi
    return 0
}

function sshUndo () {
    set +e
    ssh ${user}@${host} "
    action=${action}
    targetResource=${targetResource}
    sequence=${sequence}
    executeProfile=${executeProfile}
    targetBundleDir=${targetBundleDir}
    targetBundleEntryScript=${targetBundleEntryScript}
    barEqual30=${barEqual30}
    $(typeset -f checkIpAddress)
    $(typeset -f checkUser)
    $(typeset -f checkRevoker)
    $(typeset -f logger)
    $(typeset -f undo)
    undo
    "
    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
    logger "Succeed ${action} ${targetBundle}"
    set -e
    return 0
}

function redo (){
    set -e
    undo
    if (( $? != 0 ));then
        logger "Failed undo." "error"
        return 1
    fi
    todo
    if (( $? != 0 ));then
        logger "Failed todo." "error"
        return 1
    fi
    return 0
}

function sshRedo () {
    set +e
    ssh ${user}@${host} "
    action=${action}
    targetResource=${targetResource}
    sequence=${sequence}
    executeProfile=${executeProfile}
    targetBundleDir=${targetBundleDir}
    targetBundleEntryScript=${targetBundleEntryScript}
    $(typeset -f checkIpAddress)
    $(typeset -f checkUser)
    $(typeset -f checkRevoker)
    $(typeset -f logger)
    $(typeset -f todo)
    $(typeset -f undo)
    $(typeset -f redo)
    redo
    "
    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
    logger "Succeed ${action} ${targetBundle}"
    set -e
    return 0
}

#function backup () {
#    set -e
#    #是否备份
#    if [[ -f ${targetBackupFile}  ]]; then
#        logger "Backup file already exists ${targetBackupFile}."
#        return 0
#    fi
#    #能否备份（1、保证一定能备份，空壳；2、保证备份目录一定存在）
#    mkdir -p ${targetResourceHub}/${targetResourceHome}
#    mkdir -p $(dirname ${targetBackupFile})
#    #全量备份
#    timestamp=$(date "+%Y%m%d%H%M%S")
#    tmpdir=${timestamp}
#    mkdir -p ${tmpdir}/${sequence}
#    set +e
#    #为了兼容tomcat的备份，部分路径没有权限复制
#    cp -r ${targetResourceHub}/${targetResourceHome} ${tmpdir}/${sequence}
#    logger "Backup code is $?."
#    set -e
#
#    cmd="tar -cvzf ${targetBackupFile} -C ${tmpdir} ${sequence}/${targetResourceHome}"
#    logger "${cmd}"
#    while read -r line; do logger "${line}"; done < <(${cmd} 2>&1)
#
#
#    rm -rf ${tmpdir}
#    logger "Succeed to backup ${targetResourceHub}/${targetResourceHome} to {targetBackupFile}"
#    return 0
#}
#
#function sshBackup () {
#    set +e
#    ssh ${user}@${host} "
#    action=${action}
#    targetResource=${targetResource}
#    sequence=${sequence}
#    executeProfile=${executeProfile}
#    targetBackupFile=${targetBackupFile}
#    targetResourceHub=${targetResourceHub}
#    targetResourceHome=${targetResourceHome}
#    $(typeset -f checkIpAddress)
#    $(typeset -f checkUser)
#    $(typeset -f checkRevoker)
#    $(typeset -f logger)
#    $(typeset -f backup)
#    backup
#    "
#    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
#    logger "Succeed ${action} ${targetBundle}"
#    set -e
#    return 0
#}
#
#function update() {
#    set -e
#    mkdir -p $(dirname ${flagUpdated})
#
#    #是否更新
#    if [[ -f ${flagUpdated} ]] && [[ $(cat ${flagUpdated}) == ${sequence} ]]; then
#        logger "Resource ${targetResource} home has already been updated ${targetResourceHub}/${targetResourceHome}."
#        return 0
#    fi
#    #能否更新
#    if [[ ! -f ${targetBackupFile} ]]; then
#        logger "Failed to update." "error"
#        logger "Backup file is not found ${targetBackupFile}." "error"
#        return 1
#    fi
#    if [[ ! -f ${targetBundle} ]]; then
#        logger "Failed to update." "error"
#        logger "Package is not found ${targetBundle}." "error"
#        return 1
#    fi
#    #全量/增量更新
#    if [[ $1 == 0 && ! -z ${targetResourceHome} && -d ${targetResourceHub}/${targetResourceHome} ]]; then
#        rm -rf ${targetResourceHub}/${targetResourceHome}
#    fi
#
#    cmd="tar -xvf ${targetBundle} -C ${targetResourceHub} --strip-components=1"
#    logger "${cmd}"
#    while read -r line; do logger "${line}"; done < <(${cmd} 2>&1)
#
#    echo ${sequence} > ${flagUpdated}
#    logger "Succeed to update ${targetResourceHub}/${targetResourceHome} totally."
#    return 0
#}
#
#function sshUpdate () {
#    set +e
#    ssh ${user}@${host} "
#    action=${action}
#    targetResource=${targetResource}
#    sequence=${sequence}
#    executeProfile=${executeProfile}
#    flagUpdated=${flagUpdated}
#    targetResourceHub=${targetResourceHub}
#    targetResourceHome=${targetResourceHome}
#    targetBackupFile=${targetBackupFile}
#    targetBundle=${targetBundle}
#    $(typeset -f checkIpAddress)
#    $(typeset -f checkUser)
#    $(typeset -f checkRevoker)
#    $(typeset -f logger)
#    $(typeset -f update)
#    update $1
#    "
#    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
#    logger "Succeed ${action} ${targetBundle}"
#    set -e
#    return 0
#}
#
#function updateForce() {
#    set -e
#    rm -f ${flagUpdated}
#    update $1
#}
#
#function sshUpdateForce () {
#    set +e
#    ssh ${user}@${host} "
#    action=${action}
#    targetResource=${targetResource}
#    sequence=${sequence}
#    executeProfile=${executeProfile}
#    flagUpdated=${flagUpdated}
#    targetResourceHub=${targetResourceHub}
#    targetResourceHome=${targetResourceHome}
#    targetBackupFile=${targetBackupFile}
#    targetBundle=${targetBundle}
#    $(typeset -f checkIpAddress)
#    $(typeset -f checkUser)
#    $(typeset -f checkRevoker)
#    $(typeset -f logger)
#    $(typeset -f update)
#    $(typeset -f updateForce)
#    updateForce $1
#    "
#    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
#    logger "Succeed ${action} ${targetBundle}"
#    set -e
#    return 0
#}
#
#function rollbackForce() {
#    #选择存在的任意历史版本
#    set -e
#    #能否回退
#    if [[ ! -f ${targetBackupFile} ]]; then
#        logger "Failed to rollback, backup ${targetBackupFile} not found." "error"
#        return 1
#    fi
#    #回退
#    rm -rf ${targetResourceHub}/${targetResourceHome}
#
#    cmd="tar -xvf ${targetBackupFile} -C ${targetResourceHub} --strip-components=1"
#    logger "${cmd}"
#    while read -r line; do logger "${line}"; done < <(${cmd} 2>&1)
#
#    logger "Succeed rollback."
#}
#
#function sshRollbackForce () {
#    set +e
#    ssh ${user}@${host} "
#    action=${action}
#    targetResource=${targetResource}
#    sequence=${sequence}
#    executeProfile=${executeProfile}
#    targetResourceHub=${targetResourceHub}
#    targetResourceHome=${targetResourceHome}
#    targetBackupFile=${targetBackupFile}
#    $(typeset -f checkIpAddress)
#    $(typeset -f checkUser)
#    $(typeset -f checkRevoker)
#    $(typeset -f logger)
#    $(typeset -f rollbackForce)
#    rollbackForce
#    "
#    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
#    logger "Succeed ${action} ${targetBundle}"
#    set -e
#    return 0
#}
#
#function rollback() {
#    set -e
#    #是否回退
#    if [[ -f ${flagUpdated} ]] && [[ $(cat ${flagUpdated}) == ${sequence} ]]; then
#        #能否回退
#        rollbackForce
#    else
#        logger "Execution sequence ${sequence} is different from resource sequence."
#        logger "Resource now sequence is ${sequence}"
#    fi
#}
#
#function sshRollback () {
#    set +e
#    ssh ${user}@${host} "
#    action=${action}
#    targetResource=${targetResource}
#    sequence=${sequence}
#    executeProfile=${executeProfile}
#    flagUpdated=${flagUpdated}
#    targetResourceHub=${targetResourceHub}
#    targetResourceHome=${targetResourceHome}
#    targetBackupFile=${targetBackupFile}
#    $(typeset -f checkIpAddress)
#    $(typeset -f checkUser)
#    $(typeset -f checkRevoker)
#    $(typeset -f logger)
#    $(typeset -f rollbackForce)
#    $(typeset -f rollback)
#    rollback
#    "
#    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
#    logger "Succeed ${action} ${targetBundle}"
#    set -e
#    return 0
#}

############ 应用和应用配置可分离


function backup () {

    #备份应用还是配置[[ $1 == 0 ]] 0 配置 非 0 则是应用
    #因为起停是和配置息息相关的，所以就不选择manager下区分aap-manager和appConfig-manager的方案
    #通过序号区分应用和配置即可，有时配置就在应用下，有时两者分开，比如多实例Tomcat、Nginx、三方镜像仅需管理配置文件等场景

    if [[ $1 == 0 ]]
        then
            logger "Backup config only."
            flagUpdated=${targetResourceConfigHub}/${targetResourceConfigHome}/.sequence
            targetHub=${targetResourceConfigHub}
            targetHome=${targetResourceConfigHome}
        else
            flagUpdated=${targetResourceHub}/${targetResourceHome}/.sequence
            targetHub=${targetResourceHub}
            targetHome=${targetResourceHome}
    fi


    set -e
    #是否备份
    if [[ -f ${targetBackupFile}  ]]; then
        logger "Backup file already exists ${targetBackupFile}."
        return 0
    fi
    #能否备份（1、保证一定能备份，空壳；2、保证备份目录一定存在）
    mkdir -p ${targetHub}/${targetHome}
    mkdir -p $(dirname ${targetBackupFile})
    #全量备份
    timestamp=$(date "+%Y%m%d%H%M%S")
    tmpdir=${timestamp}
    mkdir -p ${tmpdir}/${sequence}
    set +e
    #为了兼容tomcat的备份，部分路径没有权限复制
    cp -r ${targetHub}/${targetHome} ${tmpdir}/${sequence}/${targetBundleName}
    logger "Backup code is $?."
    set -e

    cmd="tar -cvzf ${targetBackupFile} -C ${tmpdir} ${sequence}/${targetBundleName}"
    logger "${cmd}"
    while read -r line; do logger "${line}"; done < <(${cmd} 2>&1)

    rm -rf ${tmpdir}

    logger "Succeed to backup ${targetHub}/${targetHome} to ${targetBackupFile}"

    return 0
}


function sshBackup () {
    set +e
    ssh ${user}@${host} "
    action=${action}
    targetResource=${targetResource}
    sequence=${sequence}
    executeProfile=${executeProfile}
    targetBundleName=${targetBundleName}
    targetBackupFile=${targetBackupFile}
    targetResourceHub=${targetResourceHub}
    targetResourceConfigHub=${targetResourceConfigHub}
    targetResourceHome=${targetResourceHome}
    targetResourceConfigHome=${targetResourceConfigHome}
    $(typeset -f checkIpAddress)
    $(typeset -f checkUser)
    $(typeset -f checkRevoker)
    $(typeset -f logger)
    $(typeset -f backup)
    backup $1
    "
    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
    logger "Succeed ${action} ${targetBundle}"
    set -e
    return 0
}

function update() {
    set -e

    #全量/增量[[ $1 == 0 ]] 0 全量
    #应用/配置[[ $2 == 0 ]] 0 配置
    #强制[[ $3 == 0 ]] 0 强制，删除标记
    #因为起停是和配置息息相关的，所以就不选择manager下区分aap-manager和appConfig-manager的方案
    #通过序号区分应用和配置即可，有时配置就在应用下，有时两者分开，比如多实例Tomcat、Nginx、三方镜像仅需管理配置文件等场景

    if [[ $2 == 0 ]]
        then
            logger "Update config only."
            flagUpdated=${targetResourceConfigHub}/${targetResourceConfigHome}/.sequence
            targetHub=${targetResourceConfigHub}
            targetHome=${targetResourceConfigHome}
        else
            flagUpdated=${targetResourceHub}/${targetResourceHome}/.sequence
            targetHub=${targetResourceHub}
            targetHome=${targetResourceHome}
    fi

    mkdir -p $(dirname ${flagUpdated})
    if [[ $3 == 0 && -f ${flagUpdated} ]]; then
        rm -f ${flagUpdated}
        logger "Remove updated flag."
    fi

    #是否更新
    if [[ -f ${flagUpdated} ]] && [[ $(cat ${flagUpdated}) == ${sequence} ]]; then
        logger "TargetDir has already been updated ${targetHub}/${targetHome}."
        return 0
    fi
    #能否更新
    if [[ ! -f ${targetBackupFile} ]]; then
        logger "Failed to update." "error"
        logger "Backup file is not found ${targetBackupFile}." "error"
        return 1
    fi
    if [[ ! -f ${targetBundle} ]]; then
        logger "Failed to update." "error"
        logger "Package is not found ${targetBundle}." "error"
        return 1
    fi
    #全量/增量更新
    if [[ $1 == 0 && ! -z ${targetHome} && -d ${targetHub}/${targetHome} ]]; then
        rm -rf ${targetHub}/${targetHome}
    fi

    mkdir -p ${targetHub}/${targetHome}
    cmd="tar -xvf ${targetBundle} -C ${targetHub}/${targetHome} --strip-components=2"
    logger "${cmd}"
    while read -r line; do logger "${line}"; done < <(${cmd} 2>&1)

    echo ${sequence} > ${flagUpdated}
    logger "Succeed to update ${targetHub}/${targetHome} totally."
    return 0
}

function sshUpdate () {
    set +e
    ssh ${user}@${host} "
    action=${action}
    targetResource=${targetResource}
    sequence=${sequence}
    executeProfile=${executeProfile}
    targetResourceHub=${targetResourceHub}
    targetResourceConfigHub=${targetResourceConfigHub}
    targetResourceHome=${targetResourceHome}
    targetResourceConfigHome=${targetResourceConfigHome}
    targetBackupFile=${targetBackupFile}
    targetBundle=${targetBundle}
    $(typeset -f checkIpAddress)
    $(typeset -f checkUser)
    $(typeset -f checkRevoker)
    $(typeset -f logger)
    $(typeset -f update)
    update $1 $2 $3
    "
    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
    logger "Succeed ${action} ${targetBundle}"
    set -e
    return 0
}

function rollback() {
    #选择存在的任意历史版本
    set -e

    #强制[[ $1 == 0 ]] 0 强制，选择存在的任意历史版本 非 0，仅回退当前版本
    #应用/配置[[ $2 == 0 ]] 0 强制，删除标记
    #因为起停是和配置息息相关的，所以就不选择manager下区分aap-manager和appConfig-manager的方案
    #通过序号区分应用和配置即可，有时配置就在应用下，有时两者分开，比如多实例Tomcat、Nginx、三方镜像仅需管理配置文件等场景

    if [[ $2 == 0 ]]
        then
            logger "Rollback config only."
            flagUpdated=${targetResourceConfigHub}/${targetResourceConfigHome}/.sequence
            targetHub=${targetResourceConfigHub}
            targetHome=${targetResourceConfigHome}
        else
            flagUpdated=${targetResourceHub}/${targetResourceHome}/.sequence
            targetHub=${targetResourceHub}
            targetHome=${targetResourceHome}
    fi

    #能否回退
    if [[ ! -f ${targetBackupFile} ]]; then
        logger "Failed to rollback, backup ${targetBackupFile} not found." "error"
        return 1
    fi
    if [[ $1 == 0 ]]; then
        echo ${sequence} > ${flagUpdated}
    fi
    if [[ -f ${flagUpdated} ]] && [[ ! $(cat ${flagUpdated}) == ${sequence} ]]; then
        logger "Execution sequence [${sequence}] is different from now sequence $(cat ${flagUpdated})."
        return 0
    fi

    #回退
    rm -rf ${targetHub}/${targetHome}
    mkdir -p ${targetHub}/${targetHome}

    cmd="tar -xvzf ${targetBackupFile} -C ${targetHub}/${targetHome} --strip-components=2"
    logger "${cmd}"
    while read -r line; do logger "${line}"; done < <(${cmd} 2>&1)

    logger "Succeed rollback."
}

function sshRollback () {
    set +e
    ssh ${user}@${host} "
    action=${action}
    targetResource=${targetResource}
    sequence=${sequence}
    executeProfile=${executeProfile}
    targetResourceHub=${targetResourceHub}
    targetResourceConfigHub=${targetResourceConfigHub}
    targetResourceHome=${targetResourceHome}
    targetResourceConfigHome=${targetResourceConfigHome}
    targetBackupFile=${targetBackupFile}
    $(typeset -f checkIpAddress)
    $(typeset -f checkUser)
    $(typeset -f checkRevoker)
    $(typeset -f logger)
    $(typeset -f rollbackForce)
    rollback $1 $2
    "
    if [[ ! $? == 0 ]]; then logger "Failed ${action} ${targetBundle}" "error"; return 1; fi
    logger "Succeed ${action} ${targetBundle}"
    set -e
    return 0
}